昨天提到我們的目標是建立一個 dashboard,第一步不是寫程式,是先來討論個問題:
我的訓練資料,現在到底在哪裡?
不盤不知道盤了嚇一跳—自己的日常訓練,資料居然分散在四處(真的是四個地方哈哈)不互通的地方,資料格式也相去甚遠。今天就來畫這張資料地圖,順便幫每個來源打一個「機器可讀性」的分數,因為之後要把它們全部撈進同一個地方,越難讀的,之後的篇幅也就會越多。
其實單看跑步的話,Garmin Connect 本身已經很夠用。距離、配速、心率、步頻、垂直振幅,連觸地時間都有,圖表也畫得很漂亮。以量來說它是壓倒性的第一名—一場全馬是一萬兩千多筆逐秒紀錄,這不是一般記事本可以攤開來看的資料格式。
所以它的問題不是沒有想看的資訊,而是只能在它家看。
我要做的是把跑步、重訓、體重、課表放在同一個畫面裡對照—Garmin Connect 再漂亮,它也不知道我昨天練了腿、這週體重掉了多少、教練這週開了什麼。要統整四方資訊,資料就得離開 Garmin 的雲端,進到我的系統。而「離開」這件事,就得跟 Garmin 的 API 打交道—官方 API 不是隨便就申請得到的(這個之後會提)。
而且就算拿到了,摘要 API 給你的跟 app 裡看到的也是兩回事:
{
"type": "track_running",
"start": "2026-07-21 19:01:23",
"distance_m": 5000.0,
"pace": "6:17/km",
"avg_hr": 143.0,
"max_hr": 157.0
}
平均值、最大值,就這樣。想要「每一秒的心率」還原一場比賽?那就需要去取得原始的 FIT 檔—一個二進位格式,打開來是一堆看不懂的 bytes(Day 4–5 會提及)。
機器可讀性:B+。資料很結構化,但拿到手之前要先過 API 認證這關,拿到之後還有二進位解析這關。
家中的小米體重機,官方的操作流程是:站上去 → 開 Zepp app → 資料上傳雲端 → 在 app 查閱。
但自己後來發現一件有趣的事:體重機根本沒在管你有沒有開 app。你站上去的那一刻,它就用藍牙 BLE 對外廣播體重和阻抗,廣播完就結束了,存不存資料都無所謂。
換句話說,資料不是只能在 App 和體重機螢幕上查看—每天量體重時,它其實都在家裡的空氣中免費放送,只是缺少一位知心人。所以就寫了個腳本當那個聽的人(Day 6 會提及)。
目前聽到的紀錄長這樣:
| 日期時間 | 體重 (kg) | 阻抗 (Ω) | 備註 |
|---|---|---|---|
| 2026-07-21 00:17 | 73.15 | 446 | BLE 直讀 |
機器可讀性:A 自己聽的話,體重資料格式固定。走官方 app 反而分數會下降,因為還要跟雲端 API 打交道。
這是最有「人味」的一個來源,也是比較需要思考怎麼轉換資料的部分。
如果有用 Garmin 手錶的人可能很有感:Garmin Connect 明明確實可以記重訓,錶上有肌力訓練模式可以選擇,也會自動數次數。自己前期也有嘗試使用過。但對自己來說它記不下真正想紀錄的東西:
重訓紀錄是自己在組間休息時用手機打的,發展到現在已經長出一套自己的速記語法:
- 🚀 = 該重量進步
- 🔥 = 該組接近或到力竭
8+4 @35= 力竭後降重續做(drop set),35 公斤做 8 下力竭、降重後續 4 下
實際一筆紀錄長這樣:
啞鈴胸推斜板|12;12🚀,8🔥🔥🔥,6+6|35 降20
這一筆裡藏著的資訊是:35 公斤第一組做滿 12 下而且比上次進步、第三組力竭後降重續做、力竭的程度有分級。組數次數 Garmin 記得下,但「三個火焰🔥 」跟「上次同重量只做到 10 下」這種品質註記,它沒有欄位—而對重訓來說,這些註記才是下次課表怎麼調的依據。
自己能看得懂,但對機器來說這是一串謎語:分號和逗號各是什麼意思?🔥 出現三次跟一次差在哪?「降20」是重量還是次數?
而這套語法不是設計出來的,是經驗紀錄下來的—它隨著我的訓練習慣慢慢演化,充滿了只有當事人才懂的縮寫。Day 7–8 要處理的就是這個:怎麼把一套活的、手寫的語法,變成資料庫裡乾淨的欄位,又不用讓自己在組間休息時填寫訓練表單。
機器可讀性:D。但它是所有來源裡唯一「完全屬於自己」的資料—沒有 API、沒有雲端、沒有授權問題。
跑班教練開課表的方式非常自然:
「這週四 1000 三趟,組間休兩分半,配速抓 1:36 秒/400公尺。」
教練固定會把課表貼在 LINE 記事本裡,照配速分組列出每組各自的課表—但終究是一則自然文字,沒有真正的欄位。有時候教練會視上課當下的狀況(今天狀態、天氣、場地),臨時把課表加碼或減碼,這種調整比較臨時需要自己另外文字紀錄。它是四個來源裡唯一變動性較高的—你不能 parse 一則 LINE 記事本裡的自由格式文字,更不能 parse 一句臨場喊出來的話。
但它偏偏是整個系統裡最重要的資料。因為「教練開的」是計畫,其他三個來源記的是「實際發生的」—沒有計畫,就沒有『達成率』這個概念,執行與復盤這一段比較難即時觀測。Day 15 的監督執行計畫,比的就是這兩邊。
機器可讀性:F。變動性高,各種內容也需要多加解析。
| 來源 | 格式 | 更新頻率 | 誰產生 | 機器可讀性 |
|---|---|---|---|---|
| Garmin | JSON / FIT 二進位 | 每次跑步 | 手錶 | B+ |
| 體重機 | BLE 廣播 13 bytes | 每天早上 | 體重機 | A |
| 重訓紀錄 | 自創語法的文字 | 每次重訓 | 自己 | D |
| 教練課表 | LINE 記事本文字 / 臨場口頭調整 | 每週 | 教練 | F |
問題顯而易見可讀性越高的,越不重要;越重要的,越難讀,體重機的 13 bytes 工整且乾淨,但它只是體重;教練的課表決定整週訓練,但它格式比較難解析。
這就是接下來的施工順序:先從好撈的撈起,一路往難的打,最後把最難的那個也收進來。
明天會從 Garmin 的 API 先開始打交道,明天見啦~